/*
 * 在此演示中，我们将实现一个后台任务，该任务将以 2 分钟间隔运行五次，并将消息写入错误日志。
 *
 * 在 Orchard Core 中，后台任务总是定期运行，这意味着如果您想让它们停止，您需要明确地从代码中禁用它们，
 * 或者如果启用了 OrchardCore.BackgroundTasks 功能，则从后台任务管理页面禁用它们。
 *
 * 对于调度每个任务，Orchard Core 使用 NCrontab (https://github.com/atifaziz/NCrontab) 提供指定 crontab 表达式的功能。
 * 默认情况下，任务设置为每 5 分钟执行一次 - 如前所述，它们将运行直到您禁用它们。如果您想了解有关 crontab 表达式的更多信息，
 * 可以使用此在线工具：https://crontab.guru/
 */

using Microsoft.Extensions.DependencyInjection;
using OrchardCore.BackgroundTasks;
using OrchardCore.BackgroundTasks.Services;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace Ruitu.Edu.TrainingDemo.Services;

/// <summary>
/// 演示后台任务 - 演示如何创建和配置后台任务
/// 
/// 主要用途：
/// - 演示如何创建定期运行的后台任务
/// - 展示后台任务的配置和管理
/// - 演示任务的自禁用机制
/// 
/// 使用场景：
/// - 需要定期执行维护任务
/// - 需要处理长时间运行的操作
/// - 需要自动化的系统任务
/// 
/// 设计原因：
/// - 利用 Orchard Core 的后台任务框架
/// - 支持 crontab 表达式调度
/// - 提供任务生命周期管理
/// 
/// 设计模式：
/// - 单例模式：后台任务是单例对象
/// - 依赖注入模式：通过服务提供者解析服务
/// - 配置模式：通过属性配置任务设置
/// </summary>
// 要为后台任务设置默认设置，您可以使用 BackgroundTask 属性。在这里您可以
// 使用 crontab 表达式指定频率并设置描述，该描述将显示在后台任务管理页面上。
// 如果您不想在应用程序启动后立即启动，也可以将 Enabled 设置为 false。
// 这些设置可以在后台任务管理页面上完全更新。
[BackgroundTask(Schedule = "*/2 * * * *", Description = "Demo background task that runs every 2 minutes.")]
public sealed class DemoBackgroundTask : IBackgroundTask
{
    // 设置此后台任务将被执行的最大时间。
    private const int MaxCount = 5;

    // 在私有字段中存储执行次数。由于后台任务是单例对象，这将在应用程序运行时保持其值。
    private int _count;

    /// <summary>
    /// 执行后台任务的工作
    /// </summary>
    /// <param name="serviceProvider">服务提供者</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>任务完成</returns>
    // 由于后台任务是单例，我们需要这个 IServiceProvider 实例来解析每个非单例服务。
    // 当有疑问时，只需使用这个 IServiceProvider 实例来解析所有内容，而不是通过构造函数注入服务。
    public async Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)
    {
        // 这是实现任务的地方。增加 _count 并将其打印到错误日志中并带有消息。注意
        // 有一个 IBackgroundTask 的 GetTaskName() 扩展方法，它将返回任务的技术名称。

        // 向调试输出写入消息，这样我们就可以看到此代码正在运行。当使用调试器附加运行应用程序时，
        // 这将在您的 IDE 的输出窗口中可见。
        Debug.WriteLine($"{(++_count).ToTechnicalString()}/{MaxCount}: Hello from {this.GetTaskName()}!");

        if (_count == MaxCount)
        {
            // 如果达到最大值，将其重置为 0。
            _count = 0;

            // 这是使用 BackgroundTaskManager 以编程方式禁用后台任务的示例。您可以从代码库中的任何地方使用此方法。
            // 这里您需要从服务提供者获取此服务，因为它是作用域服务，但后台任务是单例。
            var backgroundTaskManager = serviceProvider.GetService<BackgroundTaskManager>();

            // GetDefaultSettings() 扩展方法将返回您在 BackgroundTask 属性中定义的设置。
            var settings = this.GetDefaultSettings();

            // 通过将 Enabled 设置为 false 并使用 IBackgroundTaskManager 更新它，设置将存储在数据库中
            // （如果已经存储则更新），从现在开始 Orchard Core 将忽略此任务并且不会执行它。
            settings.Enable = false;
            await backgroundTaskManager.UpdateAsync(settings.Name, settings);
        }
    }
}

// 训练部分结束：后台任务

// 下一站：Events/LoginGreeting.cs
